home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Misc / msql-1.0.6 / src / msql / libmsql.c < prev    next >
C/C++ Source or Header  |  1995-05-28  |  24KB  |  1,374 lines

  1. /*
  2. **    libmsql.c    - 
  3. **
  4. **
  5. ** Copyright (c) 1993  David J. Hughes
  6. **
  7. ** Permission to use, copy, and distribute for non-commercial purposes,
  8. ** is hereby granted without fee, providing that the above copyright
  9. ** notice appear in all copies and that both the copyright notice and this
  10. ** permission notice appear in supporting documentation.
  11. **
  12. ** This software is provided "as is" without any expressed or implied warranty.
  13. **
  14. ** ID = "$Id:"
  15. **
  16. */
  17.  
  18. #include <stdio.h>
  19. #include <fcntl.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <sys/socket.h>
  23. #include <netinet/in.h>
  24. #include <arpa/inet.h>
  25.  
  26. #include <signal.h>
  27. #include <netdb.h>
  28. #include <pwd.h>
  29. #include <stdlib.h>
  30. #include <varargs.h>
  31.  
  32. #include "common/portability.h"
  33.  
  34. #ifdef HAVE_SYS_UN_H
  35. #  include <sys/un.h>
  36. #endif
  37.  
  38.  
  39. #include "common/site.h"
  40.  
  41. #ifdef MINERVA_DEBUG
  42. #  include "common/debug.h"
  43. #endif
  44.  
  45. #include "msql_priv.h"
  46. #include "errmsg.h"
  47.  
  48. #define _LIB_SOURCE
  49. #include "msql.h"
  50.  
  51.  
  52. static    char    serverInfo[80],
  53.         hostInfo[80];
  54. static    int    curServerSock,
  55.         numFields,
  56.         queryTableSize,
  57.         fieldTableSize,
  58.         protoInfo;
  59. static    m_data *tmpDataStore = NULL,
  60.         *queryData = NULL,
  61.         *fieldData = NULL;
  62.  
  63.  
  64. char    msqlErrMsg[160];
  65.  
  66. RETSIGTYPE    (*oldHandler)();
  67.  
  68.  
  69. #define    resetError()    (void)bzero(msqlErrMsg,sizeof(msqlErrMsg))
  70. #define chopError()    { char *cp; cp = msqlErrMsg+strlen(msqlErrMsg) -1; \
  71.                 if (*cp == '\n') *cp = 0;}
  72.             
  73.  
  74. extern    char    *packet;
  75.  
  76. #define safeFree(x)     {if(x) { (void)free(x); x = NULL; } }
  77.  
  78.  
  79.  
  80. /**************************************************************************
  81. **    _ msqlInitDebug
  82. **
  83. **    Purpose    : 
  84. **    Args    : 
  85. **    Returns    : 
  86. **    Notes    : 
  87. */
  88.  
  89. #define    MOD_QUERY    1
  90. #define MOD_API        2
  91. #define MOD_MALLOC    4
  92. #define MOD_ERROR    8
  93.  
  94.  
  95. static int     debugLevel=0,
  96.         debugInit = 0;
  97.  
  98. static void msqlInitDebug()
  99. {
  100.     char    *env,
  101.         *tmp,
  102.         *tok;
  103.  
  104.     env = getenv("MINERVA_DEBUG");
  105.     if(env)
  106.     {
  107.         tmp = (char *)strdup(env);
  108.     }
  109.     else
  110.         return;
  111.     printf("\n-------------------------------------------------------\n");
  112.     printf("MINERVA_DEBUG found. libmsql started with the following:-\n\n");
  113.     tok = (char *)strtok(tmp,":");
  114.     while(tok)
  115.     {
  116.         if (strcmp(tok,"msql_query") == 0)
  117.         {
  118.             debugLevel |= MOD_QUERY;
  119.             printf("Debug level : query\n");
  120.         }
  121.         if (strcmp(tok,"msql_api") == 0)
  122.         {
  123.             debugLevel |= MOD_API;
  124.             printf("Debug level : api\n");
  125.         }
  126.         if (strcmp(tok,"msql_malloc") == 0)
  127.         {
  128.             debugLevel |= MOD_MALLOC;
  129.             printf("Debug level : malloc\n");
  130.         }
  131.         tok = (char *)strtok(NULL,":");
  132.     }
  133.     safeFree(tmp);
  134.     printf("\n-------------------------------------------------------\n\n");
  135. }
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142. /**************************************************************************
  143. **    _msqlDebug
  144. **
  145. **    Purpose    : 
  146. **    Args    : 
  147. **    Returns    : 
  148. **    Notes    : 
  149. */
  150.  
  151. static void msqlDebug(va_alist)
  152.     va_dcl
  153. {
  154.         va_list args;
  155.     char    msg[1024],
  156.         *fmt;
  157.     int    module,
  158.         out = 0;
  159.  
  160.     va_start(args);
  161.     module = (int) va_arg(args, int *);
  162.     if (! (module & debugLevel))
  163.     {
  164.         va_end(args);
  165.         return;
  166.     }
  167.  
  168.     fmt = (char *)va_arg(args, char *);
  169.     if (!fmt)
  170.             return;
  171.     (void)vsprintf(msg,fmt,args);
  172.     va_end(args);
  173.     printf("[libmsql] %s",msg);
  174.     fflush(stdout);
  175. }
  176.  
  177.  
  178. /**************************************************************************
  179. **    _setServerSock     
  180. **
  181. **    Purpose    : Store the server socket currently in use
  182. **    Args    : Server socket
  183. **    Returns    : Nothing
  184. **    Notes    : The current socket is stored so that the signal
  185. **          handlers know which one to shut down.
  186. */
  187.  
  188. static setServerSock(sock)
  189.     int    sock;
  190. {
  191.     curServerSock = sock;
  192. }
  193.  
  194.  
  195.  
  196.  
  197. /**************************************************************************
  198. **    _closeServer     
  199. **
  200. **    Purpose    : Shut down the server connection
  201. **    Args    : Server socket
  202. **    Returns    : Nothing
  203. **    Notes    : This is used by msqlClose and the signal handlers
  204. */
  205.  
  206. static closeServer(sock)
  207.     int    sock;
  208. {
  209.     msqlDebug(MOD_API,"Server socket (%d) closed\n", sock);
  210.     shutdown(sock,2);
  211.     close(sock);
  212. }
  213.  
  214.  
  215.  
  216.  
  217.  
  218. /**************************************************************************
  219. **    _msqlClose
  220. **
  221. **    Purpose    : Send a QUIT to the server and close the connection
  222. **    Args    : Server socket
  223. **    Returns    : Nothing
  224. **    Notes    : 
  225. */
  226.  
  227. void msqlClose(sock)
  228.     int    sock;
  229. {
  230.     char    buf[6];
  231.  
  232.     setServerSock(sock);
  233.     sprintf(packet,"%d:\n",QUIT);
  234.     writePkt(sock);
  235.     closeServer(sock);
  236. }
  237.  
  238.  
  239.  
  240.  
  241.  
  242. /**************************************************************************
  243. **    _pipeHandler
  244. **
  245. **    Purpose    : Close the server connection if we get a SIGPIPE
  246. **    Args    : sig
  247. **    Returns    : Nothing
  248. **    Notes    : 
  249. */
  250.  
  251. RETSIGTYPE pipeHandler(sig)
  252.     int    sig;
  253. {
  254.     msqlDebug(MOD_API,"Hit by pipe signal\n");
  255.     closeServer(curServerSock);
  256. }
  257.  
  258.  
  259.  
  260.  
  261. static freeQueryData(cur)
  262.     m_data    *cur;
  263. {
  264.     m_data    *prev;
  265.     int    offset;
  266.  
  267.     while(cur)
  268.     {
  269.         offset = 0;
  270.         while(offset < cur->width)
  271.         {
  272.             safeFree(cur->data[offset]);
  273.             offset++;
  274.         }
  275.         safeFree(cur->data);
  276.         prev = cur;
  277.         cur = cur->next;
  278.         safeFree(prev);
  279.         msqlDebug(MOD_MALLOC, "Query data row - free @ %X\n", prev);
  280.     }
  281.     safeFree(cur);
  282. }
  283.  
  284.  
  285.  
  286.  
  287.  
  288. static freeFieldList(fieldData)
  289.     m_fdata    *fieldData;
  290. {
  291.     m_fdata    *cur,
  292.         *prev;
  293.  
  294.     cur = fieldData;
  295.     while(cur)
  296.     {
  297.         prev = cur;
  298.         cur = cur->next;
  299.         safeFree(prev->field.table);
  300.         safeFree(prev->field.name);
  301.         safeFree(prev);
  302.         msqlDebug(MOD_MALLOC, "Field List Entry- free @ %X\n", prev);
  303.     }
  304. }
  305.  
  306.  
  307.  
  308. /**************************************************************************
  309. **    _msqlFreeResult
  310. **
  311. **    Purpose    : Free the memory allocated to a table returned by a select
  312. **    Args    : Pointer to head of table
  313. **    Returns    : Nothing
  314. **    Notes    : 
  315. */
  316.  
  317. void msqlFreeResult(result)
  318.     m_result  *result;
  319. {
  320.     freeQueryData(result->queryData);
  321.     freeFieldList(result->fieldData);
  322.     safeFree(result);
  323.     msqlDebug(MOD_MALLOC,"Result Handle - Free @ %X\n",result);
  324. }
  325.  
  326.         
  327.  
  328. static m_fdata *tableToFieldList(data)
  329.     m_data    *data;
  330. {
  331.     m_data    *curRow;
  332.     m_fdata    *curField,
  333.         *prevField,
  334.         *head = NULL;
  335.  
  336.     curRow = data;
  337.     while(curRow)
  338.     {
  339.         curField = (m_fdata *)malloc(sizeof(m_fdata));
  340.         msqlDebug(MOD_MALLOC,"Field List Entry - malloc @ %X of %d\n",
  341.             curField, sizeof(m_fdata));
  342.         (void)bzero(curField, sizeof(m_fdata));
  343.         if (head)
  344.         {
  345.             prevField->next = curField;
  346.             prevField = curField;
  347.         }
  348.         else
  349.         {
  350.             head = prevField = curField;
  351.         }
  352.  
  353.         curField->field.table = (char *)strdup(curRow->data[0]);
  354.         curField->field.name = (char *)strdup(curRow->data[1]);
  355.         curField->field.type = atoi((char*)curRow->data[2]);
  356.         curField->field.length = atoi((char*)curRow->data[3]);
  357.         curField->field.flags = 0;
  358.         if (*curRow->data[4] == 'Y')
  359.             curField->field.flags |= NOT_NULL_FLAG;
  360.         if (*curRow->data[5] == 'Y')
  361.             curField->field.flags |= PRI_KEY_FLAG;
  362.         curRow = curRow->next;
  363.     }
  364.     return(head);
  365. }
  366.  
  367.  
  368. /**************************************************************************
  369. **    _msqlConnect
  370. **
  371. **    Purpose    : Form a connection to a mSQL server
  372. **    Args    : hostname of server
  373. **    Returns    : socket for further use.  -1 on error
  374. **    Notes    : If host == NULL, localhost is used via UNIX domain socket
  375. */
  376.  
  377. int msqlConnect(host)
  378.     char    *host;
  379. {
  380.     char    *cp,
  381.         *envVar,
  382.         *unixPort;
  383.     struct    sockaddr_in IPaddr;
  384.  
  385. #ifdef HAVE_SYS_UN_H
  386.     struct    sockaddr_un UNIXaddr;
  387. #endif
  388.         struct  servent         *serv_ptr;
  389.     struct    hostent *hp;
  390.     u_long    IPAddr;
  391.     int    opt,
  392.         version,
  393.         sock,
  394.         tcpPort;
  395.     struct    passwd *pw;
  396.  
  397.  
  398.     resetError();
  399.     initNet();
  400.     if (!debugInit)
  401.     {
  402.         debugInit++;
  403.         msqlInitDebug();
  404.     }
  405.  
  406.     /*
  407.     ** Grab a socket and connect it to the server
  408.     */
  409.  
  410. #ifndef HAVE_SYS_UN_H
  411.     if (!host)
  412.     {
  413.         host = "localhost";
  414.     }
  415. #endif
  416.  
  417.     if (!host)
  418.     {
  419. #ifdef HAVE_SYS_UN_H
  420.         /* Shouldn't get in here with UNIX socks */
  421.             unixPort = MSQL_UNIX_ADDR;
  422.             if ((envVar = getenv("MSQL_UNIX_PORT")))
  423.             {
  424.                     unixPort = envVar;
  425.             }
  426.         strcpy(hostInfo,"Localhost via UNIX socket");
  427.         msqlDebug(MOD_API,"Server name = NULL.  Using UNIX sock(%s)\n",
  428.             unixPort);
  429.         sock = socket(AF_UNIX,SOCK_STREAM,0);
  430.         if (sock < 0)
  431.         {
  432.             sprintf(msqlErrMsg,SOCKET_ERROR);
  433.             return(-1);
  434.         }
  435.         setServerSock(sock);
  436.         opt = 1;
  437.         setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, 
  438.             sizeof(opt));
  439.  
  440.         (void)bzero(&UNIXaddr,sizeof(UNIXaddr));
  441.         UNIXaddr.sun_family = AF_UNIX;
  442.         strcpy(UNIXaddr.sun_path, unixPort);
  443.         if(connect(sock,(struct sockaddr *) &UNIXaddr, 
  444.             sizeof(UNIXaddr))<0)
  445.         {
  446.             sprintf(msqlErrMsg,CONNECTION_ERROR);
  447.             close(sock);
  448.             return(-1);
  449.         }
  450. #endif
  451.     }
  452.     else
  453.     {
  454.             tcpPort = MSQL_PORT;
  455.             if ((serv_ptr = getservbyname("msql", "tcp")))
  456.             {
  457.                     tcpPort = serv_ptr->s_port;
  458.             }
  459.             if ((envVar = getenv("MSQL_TCP_PORT")))
  460.             {
  461.                     tcpPort = atoi(envVar);
  462.             }
  463.  
  464.         sprintf(hostInfo,"%s via TCP/IP",host);
  465.         msqlDebug(MOD_API,"Server name = %s.  Using TCP sock (%d)\n",
  466.             host, tcpPort);
  467.         sock = socket(AF_INET,SOCK_STREAM,0);
  468.         if (sock < 0)
  469.         {
  470.             sprintf(msqlErrMsg,IPSOCK_ERROR);
  471.             return(-1);
  472.         }
  473.         setServerSock(sock);
  474.         opt = 1;
  475.         setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, 
  476.             sizeof(opt));
  477.  
  478.         (void)bzero(&IPaddr,sizeof(IPaddr));
  479.         IPaddr.sin_family = AF_INET;
  480.  
  481.         /*
  482.         ** The server name may be a host name or IP address
  483.         */
  484.     
  485.         if ((IPAddr = inet_addr(host)) != -1)
  486.         {
  487.             bcopy(&IPAddr,&IPaddr.sin_addr,sizeof(IPAddr));
  488.         }
  489.         else
  490.         {
  491.             hp = gethostbyname(host);
  492.             if (!hp)
  493.             {
  494.                 sprintf(msqlErrMsg,
  495.                     UNKNOWN_HOST,
  496.                     host);
  497.                 close(sock);
  498.                 return(-1);
  499.             }
  500.             bcopy(hp->h_addr,&IPaddr.sin_addr, hp->h_length);
  501.         }
  502.         IPaddr.sin_port = htons(tcpPort);
  503.         if(connect(sock,(struct sockaddr *) &IPaddr, 
  504.             sizeof(IPaddr))<0)
  505.         {
  506.             sprintf(msqlErrMsg,CONN_HOST_ERROR, host);
  507.             perror("Connect");
  508.             close(sock);
  509.             return(-1);
  510.         }
  511.     }
  512.  
  513.     oldHandler = signal(SIGPIPE,pipeHandler);
  514.     msqlDebug(MOD_API,"Connection socket = %d\n",sock);
  515.  
  516.     /*
  517.     ** Check the greeting message and save the version info
  518.     */
  519.  
  520.     if(readPkt(sock) <= 0)
  521.     {
  522.         closeServer(sock);
  523.         strcpy(msqlErrMsg,SERVER_GONE_ERROR);
  524.         return(-1);
  525.     }
  526.  
  527.  
  528.     /*
  529.     ** Check the result.  First check the status code from the
  530.     ** server and then the protocol version.  If the status == -1
  531.     ** or the protocol doesn't match our version, bail out!
  532.     */
  533.  
  534.     if (atoi(packet) == -1)  
  535.     {
  536.         if (cp = (char *)index(packet,':'))
  537.         {
  538.             strcpy(msqlErrMsg,cp+1);
  539.             chopError();
  540.         }
  541.         else
  542.         {
  543.             strcpy(msqlErrMsg,UNKNOWN_ERROR);
  544.         }
  545.         closeServer(sock);
  546.         return(-1);
  547.     }
  548.  
  549.     
  550.     cp = (char *)index(packet,':');
  551.     if (!cp)
  552.     {
  553.         strcpy(msqlErrMsg,PACKET_ERROR);
  554.         closeServer(sock);
  555.         return(-1);
  556.     }
  557.     version = atoi(cp + 1);
  558.     if (version != PROTOCOL_VERSION) 
  559.     {
  560.         sprintf(msqlErrMsg, VERSION_ERROR, version, PROTOCOL_VERSION);
  561.         closeServer(sock);
  562.         return(-1);
  563.     }
  564.     msqlDebug(MOD_API,"mSQL protocol version - API=%d, server=%d\n",
  565.         PROTOCOL_VERSION, version);
  566.     protoInfo = version;
  567.     cp = (char *)index(cp+1,':');
  568.     if (cp)
  569.     {
  570.         msqlDebug(MOD_API,"Server greeting = '%s'\n",cp+1);
  571.         strcpy(serverInfo,cp+1);
  572.     }
  573.     else
  574.     {
  575.         strcpy(serverInfo,"Error in server handshake!");
  576.     }
  577.     if (*(serverInfo+strlen(cp+1)-1) == '\n')
  578.     {
  579.         *(serverInfo+strlen(cp+1)-1) = 0;
  580.     }
  581.  
  582.  
  583.     /*
  584.     ** Send the username for this process for ACL checks
  585.     */
  586.     pw = getpwuid(getuid());
  587.     if (!pw)
  588.     {
  589.         strcpy(msqlErrMsg,USERNAME_ERROR);
  590.         closeServer(sock);
  591.         return(-1);
  592.     }
  593.     (void)sprintf(packet,"%s\n",pw->pw_name);
  594.     writePkt(sock);
  595.     (void)bzero(packet,PKT_LEN);
  596.     if(readPkt(sock) <= 0)
  597.     {
  598.         closeServer(sock);
  599.         strcpy(msqlErrMsg,SERVER_GONE_ERROR);
  600.         return(-1);
  601.     }
  602.  
  603.  
  604.     /*
  605.     ** Check the result
  606.     */
  607.  
  608.     if (atoi(packet) == -1)
  609.     {
  610.         char    *cp;
  611.  
  612.         cp = (char *)index(packet,':');
  613.         if (cp)
  614.         {
  615.             strcpy(msqlErrMsg,cp+1);
  616.             chopError();
  617.         }
  618.         else
  619.         {
  620.             strcpy(msqlErrMsg,UNKNOWN_ERROR);
  621.         }
  622.         closeServer(sock);
  623.         return(-1);
  624.     }
  625.     return(sock);
  626. }
  627.  
  628.  
  629.  
  630.  
  631.  
  632.  
  633. /**************************************************************************
  634. **    _msqlInitDB
  635. **
  636. **    Purpose    : Tell the server which database we want to use
  637. **    Args    : Server sock and DB name
  638. **    Returns    : -1 on error
  639. **    Notes    : 
  640. */
  641.  
  642. int msqlSelectDB(sock,db)
  643.     int    sock;
  644.     char    *db;
  645. {
  646.     int    res;
  647.  
  648.  
  649.  
  650.         msqlDebug(MOD_API,"Select Database = \"%s\"\n",db);
  651.  
  652.     resetError();
  653.     setServerSock(sock);
  654.     
  655.     /*
  656.     ** Issue the init DB command
  657.     */
  658.  
  659.     (void)sprintf(packet,"%d:%s\n",INIT_DB,db);
  660.     writePkt(sock);
  661.     (void)bzero(packet,PKT_LEN);
  662.     if(readPkt(sock) <= 0)
  663.     {
  664.         closeServer(sock);
  665.         strcpy(msqlErrMsg,SERVER_GONE_ERROR);
  666.         return(-1);
  667.     }
  668.  
  669.  
  670.     /*
  671.     ** Check the result
  672.     */
  673.  
  674.     if (atoi(packet) == -1)
  675.     {
  676.         char    *cp;
  677.  
  678.         cp = (char *)index(packet,':');
  679.         if (cp)
  680.         {
  681.             strcpy(msqlErrMsg,cp+1);
  682.             chopError();
  683.         }
  684.         else
  685.         {
  686.             strcpy(msqlErrMsg,UNKNOWN_ERROR);
  687.         }
  688.         return(-1);
  689.     }
  690.  
  691.     return(0);
  692. }
  693.  
  694.  
  695.  
  696.  
  697.  
  698. /**************************************************************************
  699. **    _msqlStoreResult
  700. **
  701. **    Purpose    : Store the data returned from a query
  702. **    Args    : None
  703. **    Returns    : Result handle or NULL if no data
  704. **    Notes    : 
  705. */
  706.  
  707. m_result *msqlStoreResult()
  708. {
  709.     m_result *tmp;
  710.  
  711.     if (!queryData && !fieldData)
  712.     {
  713.         return(NULL);
  714.     }
  715.     tmp = (m_result *)malloc(sizeof(m_result));
  716.     msqlDebug(MOD_MALLOC,"Result Handle - malloc @ %X of %d\n",
  717.         tmp, sizeof(m_result));
  718.     if (!tmp)
  719.     {
  720.         return(NULL);
  721.     }
  722.     (void)bzero(tmp, sizeof(m_result));
  723.     tmp->queryData = queryData;
  724.     tmp->numRows = queryTableSize;
  725.     tmp->fieldData = tableToFieldList(fieldData);
  726.     tmp->numFields = fieldTableSize;
  727.     tmp->cursor = tmp->queryData;
  728.     tmp->fieldCursor = tmp->fieldData;
  729.     freeQueryData(fieldData);
  730.     queryData = NULL;
  731.     fieldData = NULL;
  732.     return(tmp);
  733. }
  734.  
  735.  
  736.  
  737.  
  738.  
  739. /**************************************************************************
  740. **    _msqlFetchField
  741. **
  742. **    Purpose    : Return a row of the query results
  743. **    Args    : result handle
  744. **    Returns    : pointer to row data
  745. **    Notes    : 
  746. */
  747.  
  748. m_field    *msqlFetchField(handle)
  749.     m_result *handle;
  750. {
  751.     m_field    *tmp;
  752.  
  753.     if (!handle->fieldCursor)
  754.     {
  755.         return(NULL);
  756.     }
  757.     tmp = &(handle->fieldCursor->field);
  758.     handle->fieldCursor = handle->fieldCursor->next;
  759.     return(tmp);
  760. }
  761.  
  762.  
  763.  
  764. /**************************************************************************
  765. **    _msqlFetchRow
  766. **
  767. **    Purpose    : Return a row of the query results
  768. **    Args    : result handle
  769. **    Returns    : pointer to row data
  770. **    Notes    : 
  771. */
  772.  
  773. m_row    msqlFetchRow(handle)
  774.     m_result *handle;
  775. {
  776.     m_row    tmp;
  777.  
  778.     if (!handle->cursor)
  779.     {
  780.         return(NULL);
  781.     }
  782.     tmp = handle->cursor->data;
  783.     handle->cursor = handle->cursor->next;
  784.     return(tmp);
  785. }
  786.  
  787.  
  788.  
  789.  
  790. /**************************************************************************
  791. **    _msqlFieldSeek
  792. **
  793. **    Purpose    : Move the result cursor
  794. **    Args    : result handle, offset
  795. **    Returns    : Nothing.  Just sets the cursor
  796. **    Notes    : The data is a single linked list so we can go backwards
  797. */
  798.  
  799. void msqlFieldSeek(handle, offset)
  800.     m_result *handle;
  801.     int    offset;
  802. {
  803.     m_fdata    *tmp;
  804.  
  805.     
  806.     msqlDebug(MOD_API,"msqlFieldSeek() pos = \n",offset);
  807.     tmp = handle->fieldData;
  808.     while(offset)
  809.     {
  810.         if (!tmp)
  811.             break;
  812.         tmp = tmp->next;
  813.         offset--;
  814.     }
  815.     handle->fieldCursor = tmp;
  816. }
  817.  
  818. /**************************************************************************
  819. **    _msqlDataSeek
  820. **
  821. **    Purpose    : Move the result cursor
  822. **    Args    : result handle, offset
  823. **    Returns    : Nothing.  Just sets the cursor
  824. **    Notes    : The data is a single linked list so we can go backwards
  825. */
  826.  
  827. void msqlDataSeek(handle, offset)
  828.     m_result *handle;
  829.     int    offset;
  830. {
  831.     m_data    *tmp;
  832.  
  833.     
  834.     msqlDebug(MOD_API,"msqlDataSeek() pos = \n",offset);
  835.     tmp = handle->queryData;
  836.     while(offset)
  837.     {
  838.         if (!tmp)
  839.             break;
  840.         tmp = tmp->next;
  841.         offset--;
  842.     }
  843.     handle->cursor = tmp;
  844. }
  845.  
  846.  
  847.  
  848. /**************************************************************************
  849. **    _
  850. **
  851. **    Purpose    : 
  852. **    Args    : 
  853. **    Returns    : 
  854. **    Notes    : 
  855. */
  856.  
  857. int msqlQuery(sock,q)
  858.     int    sock;
  859.     char    *q;
  860. {
  861.     int    len,
  862.         res;
  863.     char    *cp;
  864.     
  865.  
  866.  
  867.         msqlDebug(MOD_QUERY,"Query = \"%s\"\n",q);
  868.     resetError();
  869.     setServerSock(sock);
  870.  
  871.     /*
  872.     ** Issue the query
  873.     */
  874.  
  875.     (void)sprintf(packet,"%d:%s\n",QUERY,q);
  876.     writePkt(sock);
  877.     (void)bzero(packet,PKT_LEN);
  878.     if(readPkt(sock) <= 0)
  879.     {
  880.         closeServer(sock);
  881.         strcpy(msqlErrMsg,SERVER_GONE_ERROR);
  882.         return(-1);
  883.     }
  884.  
  885.  
  886.     /*
  887.     ** Check the result.  It may be an indication of further data to
  888.     ** come (ie. from a select)
  889.     */
  890.  
  891.     if (atoi(packet) == -1)
  892.     {
  893.         cp = (char *)index(packet,':');
  894.         if (cp)
  895.         {
  896.             strcpy(msqlErrMsg,cp+1);
  897.             chopError();
  898.         }
  899.         else
  900.         {
  901.             strcpy(msqlErrMsg,UNKNOWN_ERROR);
  902.         }
  903.         return(-1);
  904.     }
  905.  
  906.     cp = (char *)index(packet,':');
  907.     numFields = 0;
  908.     if (cp)
  909.     {
  910.         numFields = atoi(cp+1);
  911.         if (numFields <= 0)
  912.             return(0);
  913.     }
  914.     else
  915.     {
  916.         return(0);
  917.     }
  918.  
  919.     /*
  920.     ** numFields > 0 therefore we have data waiting on the socket.
  921.     ** Grab it and dump it into a table structure.  If there's
  922.     ** uncollected data free it - it's no longer available.
  923.     */
  924.     if (queryData)
  925.     {
  926.         freeQueryData(queryData);
  927.         freeQueryData(fieldData);
  928.         queryData = NULL;
  929.         fieldData = NULL;
  930.     }
  931.  
  932.     queryTableSize = readQueryData(sock);
  933.     if (queryTableSize < 0)
  934.     {
  935.         return(-1);
  936.     }
  937.     queryData = tmpDataStore;
  938.     tmpDataStore = NULL;
  939.     numFields = 6;
  940.     fieldTableSize = readQueryData(sock);
  941.     if (fieldTableSize < 0)
  942.     {
  943.         return(-1);
  944.     }
  945.     fieldData = tmpDataStore;
  946.     tmpDataStore = NULL;
  947.     return(0);
  948. }
  949.  
  950.  
  951.  
  952.  
  953. /**************************************************************************
  954. **    _
  955. **
  956. **    Purpose    : 
  957. **    Args    : 
  958. **    Returns    : 
  959. **    Notes    : 
  960. */
  961.  
  962. int readQueryData(sock)
  963.     int    sock;
  964. {
  965.     int    off,
  966.         len,
  967.         numRows;
  968.     char    *cp;
  969.     m_data    *cur;
  970.     
  971.     if (readPkt(sock) <= 0)
  972.     {
  973.         closeServer(sock);
  974.         strcpy(msqlErrMsg,SERVER_GONE_ERROR);
  975.         return(-1);
  976.     }
  977.  
  978.     numRows = 0;
  979.     while(atoi(packet) != -100)
  980.     {
  981.         if (atoi(packet) == -1)
  982.         {
  983.             cp = (char *)index(packet,':');
  984.             if (cp)
  985.             {
  986.                 strcpy(msqlErrMsg,cp+1);
  987.                 chopError();
  988.             }    
  989.             else
  990.             {
  991.                 strcpy(msqlErrMsg,UNKNOWN_ERROR);
  992.             }
  993.             return(-1);
  994.         }
  995.         numRows++;
  996.         if(!tmpDataStore)
  997.         {
  998.             tmpDataStore = cur = (m_data *)malloc(sizeof(m_data));
  999.         }
  1000.         else
  1001.         {
  1002.             cur->next = (m_data *)malloc(sizeof(m_data));
  1003.             cur = cur->next;
  1004.         }
  1005.         msqlDebug(MOD_MALLOC,"Query data row - malloc @ %X of %d\n",
  1006.             cur, sizeof(m_data));
  1007.         (void)bzero(cur,sizeof(m_data));
  1008.         cur->data = (u_char **)malloc(numFields * sizeof(char *));
  1009.         (void)bzero(cur->data,numFields * sizeof(char *));
  1010.         cur->width = numFields;
  1011.         off = 0;
  1012.         cp = packet;
  1013.         while(off < numFields)
  1014.         {
  1015.             len = atoi(cp);
  1016.             cp = (char *)index(cp,':');
  1017.             if (len == -1)
  1018.             {
  1019.                 cur->data[off] = (u_char *)NULL;
  1020.                 cp++;
  1021.             }
  1022.             else
  1023.             {
  1024.                 cur->data[off] = (u_char *)malloc(len+1);
  1025.                 (void)bzero(cur->data[off],len+1);
  1026.                 (void)bcopy(cp+1,cur->data[off],len);
  1027.                 cp += len + 1;
  1028.             }
  1029.             off++;
  1030.         }
  1031.  
  1032.         if (readPkt(sock) <= 0)
  1033.         {
  1034.             closeServer(sock);
  1035.             strcpy(msqlErrMsg,SERVER_GONE_ERROR);
  1036.             return(-1);
  1037.         }
  1038.     }
  1039.     return(numRows);
  1040. }
  1041.  
  1042.  
  1043.  
  1044.  
  1045.  
  1046.  
  1047. /**************************************************************************
  1048. **    _
  1049. **
  1050. **    Purpose    : 
  1051. **    Args    : 
  1052. **    Returns    : 
  1053. **    Notes    : 
  1054. */
  1055.  
  1056. m_result *msqlListDBs(sock)
  1057.     int    sock;
  1058. {
  1059.     m_result *tmp;
  1060.  
  1061.     msqlDebug(MOD_API,"msqlListDBs(%d)\n",sock);
  1062.     tmp = (m_result *)malloc(sizeof(m_result));
  1063.     if (!tmp)
  1064.     {
  1065.         return(NULL);
  1066.     }
  1067.     (void)bzero(tmp, sizeof(m_result));
  1068.     msqlDebug(MOD_MALLOC,"Result Handle - malloc @ %X of %d\n",
  1069.         tmp, sizeof(m_result));
  1070.     sprintf(packet,"%d:\n",DB_LIST);
  1071.     writePkt(sock);
  1072.     numFields = 1;
  1073.     tmp->numRows = readQueryData(sock);
  1074.     if (tmp->numRows < 0)
  1075.     {
  1076.         (void)free(tmp);
  1077.         return(NULL);
  1078.     }
  1079.     tmp->queryData = tmpDataStore;
  1080.     tmp->cursor = tmp->queryData;
  1081.     tmp->numFields = 1;
  1082.     tmp->fieldData = (m_fdata *)malloc(sizeof(m_fdata));
  1083.     msqlDebug(MOD_MALLOC,"Field List Entry - malloc @ %X of %d\n",
  1084.         tmp->fieldData, sizeof(m_fdata));
  1085.     (void)bzero(tmp->fieldData, sizeof(m_fdata));
  1086.     tmp->fieldData->field.table = (char *)strdup("mSQL Catalog");
  1087.     tmp->fieldData->field.name = (char *)strdup("Database");
  1088.     tmp->fieldData->field.type = CHAR_TYPE;
  1089.     tmp->fieldData->field.length = NAME_LEN;
  1090.     tmp->fieldData->field.flags = 0;
  1091.     tmp->fieldCursor = tmp->fieldData;
  1092.     tmpDataStore = NULL;
  1093.     return(tmp);
  1094. }
  1095.  
  1096.  
  1097.  
  1098.  
  1099.  
  1100. /**************************************************************************
  1101. **    _
  1102. **
  1103. **    Purpose    : 
  1104. **    Args    : 
  1105. **    Returns    : 
  1106. **    Notes    : 
  1107. */
  1108.  
  1109. m_result *msqlListTables(sock)
  1110.     int    sock;
  1111. {
  1112.     m_result *tmp;
  1113.  
  1114.     msqlDebug(MOD_API,"msqlListTables(%d)\n",sock);
  1115.     tmp = (m_result *)malloc(sizeof(m_result));
  1116.     if (!tmp)
  1117.     {
  1118.         return(NULL);
  1119.     }
  1120.     msqlDebug(MOD_MALLOC,"Result Handle - malloc @ %X of %d\n",
  1121.         tmp, sizeof(m_result));
  1122.     (void)bzero(tmp, sizeof(m_result));
  1123.     sprintf(packet,"%d:\n",TABLE_LIST);
  1124.     writePkt(sock);
  1125.     numFields = 1;
  1126.     tmp->numRows = readQueryData(sock);
  1127.     if (tmp->numRows < 0)
  1128.     {
  1129.         (void)free(tmp);
  1130.         return(NULL);
  1131.     }
  1132.     tmp->queryData = tmpDataStore;
  1133.     tmp->numFields = 0;
  1134.     tmp->cursor = tmp->queryData;
  1135.     tmp->fieldCursor = NULL;
  1136.     tmpDataStore = NULL;
  1137.     tmp->numFields = 1;
  1138.     tmp->fieldData = (m_fdata *)malloc(sizeof(m_fdata));
  1139.     msqlDebug(MOD_MALLOC,"Field List Entry - malloc @ %X of %d\n",
  1140.         tmp->fieldData, sizeof(m_fdata));
  1141.     (void)bzero(tmp->fieldData, sizeof(m_fdata));
  1142.     tmp->fieldData->field.table = (char *)strdup("mSQL Catalog");
  1143.     tmp->fieldData->field.name = (char *)strdup("Table");
  1144.     tmp->fieldData->field.type = CHAR_TYPE;
  1145.     tmp->fieldData->field.length = NAME_LEN;
  1146.     tmp->fieldData->field.flags = 0;
  1147.     tmp->fieldCursor = tmp->fieldData;
  1148.     return(tmp);
  1149. }
  1150.  
  1151.  
  1152. /**************************************************************************
  1153. **    _
  1154. **
  1155. **    Purpose    : 
  1156. **    Args    : 
  1157. **    Returns    : 
  1158. **    Notes    : 
  1159. */
  1160.  
  1161. m_result *msqlListFields(sock,table)
  1162.     int    sock;
  1163.     char    *table;
  1164. {
  1165.     m_result *tmp;
  1166.  
  1167.     msqlDebug(MOD_API,"msqlListFields(%d,%s)\n",sock,table);
  1168.     tmp = (m_result *)malloc(sizeof(m_result));
  1169.     if (!tmp)
  1170.     {
  1171.         return(NULL);
  1172.     }
  1173.     msqlDebug(MOD_MALLOC,"Result Handle - malloc @ %X of %d\n",
  1174.         tmp, sizeof(m_result));
  1175.     (void)bzero(tmp, sizeof(m_result));
  1176.     sprintf(packet,"%d:%s\n",FIELD_LIST,table);
  1177.     writePkt(sock);
  1178.     numFields = 6;
  1179.     tmp->numFields = readQueryData(sock);
  1180.     if(tmp->numFields < 0)
  1181.     {
  1182.         (void)free(tmp);
  1183.         return(NULL);
  1184.     }
  1185.     tmp->fieldData = tableToFieldList(tmpDataStore);
  1186.     tmp->fieldCursor = tmp->fieldData;
  1187.     tmp->queryData = NULL;
  1188.     tmp->cursor = NULL;
  1189.     tmp->numRows = 0;
  1190.     tmpDataStore = NULL;
  1191.     freeQueryData(tmpDataStore);
  1192.     return(tmp);
  1193. }
  1194.  
  1195.  
  1196.  
  1197.  
  1198. int msqlCreateDB(sock,DB)
  1199.     int    sock;
  1200.     char    *DB;
  1201. {
  1202.     char    *cp;
  1203.  
  1204.     msqlDebug(MOD_API,"msqlCreateDB(%d,%s)\n",sock,DB);
  1205.     sprintf(packet,"%d:%s\n",CREATE_DB,DB);
  1206.     writePkt(sock);
  1207.     (void)bzero(packet,PKT_LEN);
  1208.     if(readPkt(sock) <= 0)
  1209.     {
  1210.         closeServer(sock);
  1211.         strcpy(msqlErrMsg,SERVER_GONE_ERROR);
  1212.         return(-1);
  1213.     }
  1214.  
  1215.  
  1216.     /*
  1217.     ** Check the result.  
  1218.     */
  1219.  
  1220.     if (atoi(packet) == -1)
  1221.     {
  1222.         cp = (char *)index(packet,':');
  1223.         if (cp)
  1224.         {
  1225.             strcpy(msqlErrMsg,cp+1);
  1226.             chopError();
  1227.         }
  1228.         else
  1229.         {
  1230.             strcpy(msqlErrMsg,UNKNOWN_ERROR);
  1231.         }
  1232.         return(-1);
  1233.     }
  1234.     return(0);
  1235. }
  1236.  
  1237. int msqlDropDB(sock,DB)
  1238.     int    sock;
  1239.     char    *DB;
  1240. {
  1241.     char    *cp;
  1242.  
  1243.     msqlDebug(MOD_API,"msqlDropDB(%d,%s)\n",sock,DB);
  1244.     sprintf(packet,"%d:%s\n",DROP_DB,DB);
  1245.     writePkt(sock);
  1246.     (void)bzero(packet,PKT_LEN);
  1247.     if(readPkt(sock) <= 0)
  1248.     {
  1249.         closeServer(sock);
  1250.         strcpy(msqlErrMsg,SERVER_GONE_ERROR);
  1251.         return(-1);
  1252.     }
  1253.  
  1254.  
  1255.     /*
  1256.     ** Check the result.  
  1257.     */
  1258.  
  1259.     if (atoi(packet) == -1)
  1260.     {
  1261.         cp = (char *)index(packet,':');
  1262.         if (cp)
  1263.         {
  1264.             strcpy(msqlErrMsg,cp+1);
  1265.             chopError();
  1266.         }
  1267.         else
  1268.         {
  1269.             strcpy(msqlErrMsg,UNKNOWN_ERROR);
  1270.         }
  1271.         return(-1);
  1272.     }
  1273.     return(0);
  1274. }
  1275.  
  1276.  
  1277. int msqlShutdown(sock)
  1278.     int    sock;
  1279. {
  1280.     char    *cp;
  1281.  
  1282.     msqlDebug(MOD_API,"msqlShutdown(%d)\n",sock);
  1283.     sprintf(packet,"%d:\n",SHUTDOWN);
  1284.     writePkt(sock);
  1285.     (void)bzero(packet,PKT_LEN);
  1286.     if(readPkt(sock) <= 0)
  1287.     {
  1288.         closeServer(sock);
  1289.         strcpy(msqlErrMsg,SERVER_GONE_ERROR);
  1290.         return(-1);
  1291.     }
  1292.  
  1293.  
  1294.     /*
  1295.     ** Check the result.  
  1296.     */
  1297.  
  1298.     if (atoi(packet) == -1)
  1299.     {
  1300.         cp = (char *)index(packet,':');
  1301.         if (cp)
  1302.         {
  1303.             strcpy(msqlErrMsg,cp+1);
  1304.             chopError();
  1305.         }
  1306.         else
  1307.         {
  1308.             strcpy(msqlErrMsg,UNKNOWN_ERROR);
  1309.         }
  1310.         return(-1);
  1311.     }
  1312.     return(0);
  1313. }
  1314.  
  1315.  
  1316.  
  1317. int msqlReloadAcls(sock)
  1318.     int    sock;
  1319. {
  1320.     char    *cp;
  1321.  
  1322.     msqlDebug(MOD_API,"msqlReloadAcl(%d)\n",sock);
  1323.     sprintf(packet,"%d:\n",RELOAD_ACL);
  1324.     writePkt(sock);
  1325.     (void)bzero(packet,PKT_LEN);
  1326.     if(readPkt(sock) <= 0)
  1327.     {
  1328.         closeServer(sock);
  1329.         strcpy(msqlErrMsg,SERVER_GONE_ERROR);
  1330.         return(-1);
  1331.     }
  1332.  
  1333.  
  1334.     /*
  1335.     ** Check the result.  
  1336.     */
  1337.  
  1338.     if (atoi(packet) == -1)
  1339.     {
  1340.         cp = (char *)index(packet,':');
  1341.         if (cp)
  1342.         {
  1343.             strcpy(msqlErrMsg,cp+1);
  1344.             chopError();
  1345.         }
  1346.         else
  1347.         {
  1348.             strcpy(msqlErrMsg,UNKNOWN_ERROR);
  1349.         }
  1350.         return(-1);
  1351.     }
  1352.     return(0);
  1353. }
  1354.  
  1355.  
  1356.  
  1357. char *msqlGetServerInfo()
  1358. {
  1359.     return(serverInfo);
  1360. }
  1361.  
  1362.  
  1363. char *msqlGetHostInfo()
  1364. {
  1365.     return(hostInfo);
  1366. }
  1367.  
  1368.  
  1369. int msqlGetProtoInfo()
  1370. {
  1371.     return(protoInfo);
  1372. }
  1373.  
  1374.